/* LEDC (LED Controller) fade example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
// #include "driver/ledc.h"
#include "esp_err.h"
#include "rgb_ws2812b.h"

/*
 * About this example
 *
 * 1. Start with initializing LEDC module:
 *    a. Set the timer of LEDC first, this determines the frequency
 *       and resolution of PWM.
 *    b. Then set the LEDC channel you want to use,
 *       and bind with one of the timers.
 *
 * 2. You need first to install a default fade function,
 *    then you can use fade APIs.
 *
 * 3. You can also set a target duty directly without fading.
 *
 * 4. On ESP32, GPIO18/19/4/5 are used as the LEDC outputs:
 *              GPIO18/19 are from the high speed channel group
 *              GPIO4/5 are from the low speed channel group
 *
 *    On other targets, GPIO8/9/4/5 are used as the LEDC outputs,
 *    and they are all from the low speed channel group.
 *
 * 5. All the LEDC outputs change the duty repeatedly.
 *
 */

/****************************************************************
 *      ws2812逻辑电平
 * -----logl 低
 * T0H   0 码， 高电平时间     220ns~380ns
 * T0L   0 码， 低电平时间     580ns~1µs
 * 
 * ------logic 高
 * T1H  1 码， 高电平时间      580ns~1µs
 * T1L  1 码， 低电平时间      580ns~1µs
 * 
 * -------logic reset
 * RES   帧单位，低电平时间     280µs 以上
******************************************************************/


 void spi_delay(int delay_cnt)
{
    int i;
    for(i = 0; i < delay_cnt; i ++){
        // __NOP();
        // asm("NOP");
        asm("NOP");
        asm("NOP");
        asm("NOP");
        asm("NOP");
    }
}


 void ws2812_logic_high(void)
{
    gpio_set_level(WS2812B_GPIO, 1);
}

 void ws2812_logic_low(void)
{
    gpio_set_level(WS2812B_GPIO, 0);
}

//  --白色
 void white_color(void)
{
    int i;

    for(i = 0; i < 24 ; i++){
        ws2812_logic_high();
        spi_delay(5);
        ws2812_logic_low();
        spi_delay(5);
    }
}

/******************************
 * --白色 带占空比 [0%~100%]
*********************************/  
void white_color_percent(uint8_t percent)
{
    int i, index;
    uint8_t tmp;

    // 绿,红，蓝，
    for(index = 0; index < 3; index++){
        tmp = percent*25/10;
        for(i = 0; i < 8 ; i++){
            if(tmp&0x80){
                ws2812_logic_high();
                spi_delay(5);
                ws2812_logic_low();
                spi_delay(5);
            }
            else{
                ws2812_logic_high();
                // __NOP();
                // __NOP();
                // __NOP();
                asm("NOP");
                asm("NOP");
                asm("NOP");
                ws2812_logic_low();
                spi_delay(5);
            }
            tmp <<= 1;

        }
    }
}



// --红色
 void red_color(void)
{
    int i;
    for(i = 0; i < 8; i++){
        ws2812_logic_high();
        // __NOP();
        // __NOP();
        // __NOP();
        asm("NOP");
        asm("NOP");
        asm("NOP");
        ws2812_logic_low();
        spi_delay(5);
    }
    for(i = 8; i < 16; i++){
        ws2812_logic_high();
        spi_delay(5);
        ws2812_logic_low();
        spi_delay(5);
    }
   for(i = 16; i < 24; i++){
        ws2812_logic_high();
        // __NOP();
        // __NOP();
        // __NOP();
        asm("NOP");
        asm("NOP");
        asm("NOP");
        ws2812_logic_low();
        spi_delay(5);
    }
}

// --绿色
 void green_color(void)
{
    int i;
    for(i = 0; i < 8; i++){
        ws2812_logic_high();
        spi_delay(5);
        ws2812_logic_low();
        spi_delay(5);
    }
    for(i = 8; i < 24; i++){
        ws2812_logic_high();
        // __NOP();
        // __NOP();
        // __NOP();
        asm("NOP");
        asm("NOP");
        asm("NOP");
        asm("NOP");
        ws2812_logic_low();
        spi_delay(5);
    }
}

// --蓝色
 void blue_color(void)
{
    int i;
    for(i = 0; i < 16; i++){
        ws2812_logic_high();
        // __NOP();
        // __NOP();
        // __NOP();
        asm("NOP");
        asm("NOP");
        asm("NOP");
        asm("NOP");
        ws2812_logic_low();
        spi_delay(5);
    }
    for(i = 16; i < 24; i++){
        ws2812_logic_high();
        spi_delay(5);
        ws2812_logic_low();
        spi_delay(5);
    }
}

static int rgb_cnt = 0;

void rgb_ws2812_on(void)
{
    // for(int i = 0; i < 10; i++){
    //     ws2812_logic_low();
    //     spi_delay(10);
    //     ws2812_logic_high();
    //     spi_delay(10);
    // }
//  ws2812_logic_high();
    rgb_cnt ++;

    white_color_percent(rgb_cnt%101);
    // switch(rgb_cnt%4)
    // {
    //     case 0:{
    //         white_color();
    //         break;
    //     }
    //     case 1:{
    //         red_color();
    //         break;
    //     }
    //     case 2:{
    //         green_color();
    //         break;
    //     }
    //     case 3:{
    //         blue_color();
    //         break;
    //     }
    //     default:{
    //         break;
    //     }
    // }
}

void rgb_ws2812_off(void)
{
    gpio_set_level(WS2812B_GPIO, 0);
}


void rgb_ws2812_init(void)
{
    /* Configure the IOMUX register for pad BLINK_GPIO (some pads are
       muxed to GPIO on reset already, but some default to other
       functions and need to be switched to GPIO. Consult the
       Technical Reference for a list of pads and their default
       functions.)
    */
   //  gpio_pad_select_gpio(BLINK_GPIO);
    /* Set the GPIO as a push/pull output */
   //  gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);


   gpio_config_t io_conf = {};
   //disable interrupt
   io_conf.intr_type = GPIO_INTR_DISABLE;
   //set as output mode
   io_conf.mode = GPIO_MODE_OUTPUT_OD;
   //bit mask of the pins that you want to set,e.g.21
   io_conf.pin_bit_mask = 1ULL << WS2812B_GPIO;
   //disable pull-down mode
   io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
   //disable pull-up mode
   io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
   //configure GPIO with the given settings
   gpio_config(&io_conf);
}





